﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Global.Global;
using Global.Http;
using Global.IO;
using Global.Xml;

namespace TestWebRequest
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            try
            {
                SendHttpRequest(ParseCommand(args));
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("");
                Console.WriteLine("An error as occured.");
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
            Console.ForegroundColor = ConsoleColor.Gray;

            #region test other stuff
            //SendHttpRequest();
            //SendFluentHttpRequest();
            //BuildUrl();
            //SendMail();
            //DataContractJsonSerialization();
            #endregion

            //Console.ReadLine();
        }
        private static void Header()
        {
            Console.WriteLine();
            Console.WriteLine("***************************************************************");
            Console.WriteLine("*             Name : http requester tool                      *");
            Console.WriteLine("*        Developer : Andre da Silva Carrilho                  *");
            Console.WriteLine("*             Date : 2010-06-04                               *");
            Console.WriteLine("*             Blog : http://www.acarrilho.com                 *");
            Console.WriteLine("*           Hosted : http://global.codeplex.com               *");
            Console.WriteLine("*      Source (hg) : https://hg01.codeplex.com/global         *");
            Console.WriteLine("***************************************************************");
            Console.WriteLine();
            Console.WriteLine("Type 'http -h' to display the available commands.");
            Console.WriteLine();
        }
        private static void HttpHelp()
        {
            Header();
            Console.WriteLine("How to configre the request: ");
            Console.WriteLine("  -h       (Help)");
            Console.WriteLine("           Display the list of available commands.");
            Console.WriteLine("           If this flag is present other flags will be ignored.");
            Console.WriteLine("  -u       (Url)");
            Console.WriteLine("           The request url.");
            Console.WriteLine("  -op      (OutputPath)");
            Console.WriteLine("           Outputs the response to a file.");
            Console.WriteLine("           By default the response is outputed to the console.");
            Console.WriteLine("  -m       (Method)");
            Console.WriteLine("           Http verb. Accepted verbs are GET, POSt, PUT and DELETE.");
            Console.WriteLine("           Default is GET..");
            Console.WriteLine("  -ct      (ContentType)");
            Console.WriteLine("           The content type.");
            Console.WriteLine("  -t       (Timeout)");
            Console.WriteLine("           The request timeout.");
            Console.WriteLine("  -ua      (UserAgent)");
            Console.WriteLine("           The request user agent.");
            Console.WriteLine("  -ka      (KeepAlive)");
            Console.WriteLine("           Sets the keep alive flag.");
            Console.WriteLine("  -re      (ResponseEncoding)");
            Console.WriteLine("           Encoding to be used when decoding the response. Accepted values are:");
            Console.WriteLine("              -> ASCII");
            Console.WriteLine("              -> BigEndianUnicode");
            Console.WriteLine("              -> Default");
            Console.WriteLine("              -> Unicode");
            Console.WriteLine("              -> UTF32");
            Console.WriteLine("              -> UTF7");
            Console.WriteLine("              -> UTF8");
            Console.WriteLine("  -pde     (PostDataEncoding)");
            Console.WriteLine("           The encoding to be used when encoding the post data.");
            Console.WriteLine("              -> ASCII");
            Console.WriteLine("              -> BigEndianUnicode");
            Console.WriteLine("              -> Default");
            Console.WriteLine("              -> Unicode");
            Console.WriteLine("              -> UTF32");
            Console.WriteLine("              -> UTF7");
            Console.WriteLine("              -> UTF8");
            Console.WriteLine("  -pdp     (PostDataPath)");
            Console.WriteLine("           The path of the file that contains the postData.");
            Console.WriteLine("           This is used for POST and PUT requests.");
            Console.WriteLine("           Typically you'd want to use xl or json.");
            Console.WriteLine("");
            Console.WriteLine("  -c:u     (Credentials:Username)");
            Console.WriteLine("           Sets the request credential username.");
            Console.WriteLine("  -c:o     (Credentials:Password)");
            Console.WriteLine("           Sets the request credential password.");
            Console.WriteLine("  -c:d     (Credentials:Domain)");
            Console.WriteLine("           Sets the request credential domain.");
            Console.WriteLine("");
            Console.WriteLine("  -ps:bl   (ProxySettings:BypssLocally)");
            Console.WriteLine("           Bypasses proxy settings for local requests.");
            Console.WriteLine("  -ps:a    (ProxySettings:Address)");
            Console.WriteLine("           Sets the proxy url address..");
            Console.WriteLine("  -ps:c:u  (Credentials:Username)");
            Console.WriteLine("           Sets the request credential username.");
            Console.WriteLine("  -ps:c:p  (Credentials:Password)");
            Console.WriteLine("           Sets the request credential password.");
            Console.WriteLine("  -ps:c:d  (Credentials:Domain)");
            Console.WriteLine("           Sets the request credential domain.");
            Console.WriteLine("  -ps:ab   (Credentials:AddBypass)");
            Console.WriteLine("           Adds bypass rules to the proxy settings.");
            Console.WriteLine("");
            Console.WriteLine("  -hd      (Headers)");
            Console.WriteLine("           Adds headers to the request.");
            Console.WriteLine("           Something similar to 'Accept-Language:da'.");
        }
        private static HttpArgs ParseCommand(string[] args)
        {
            if (args != null && args.Length > 0)
            {
                var argsObj = new HttpArgs();

                for (var i = 0; i < args.Length; i++)
                {
                    switch (args[i])
                    {
                        case "-h":
                            argsObj.Help = true;
                            break;
                        case "-u":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -u.");
                                return null;
                            }
                            argsObj.Url = args[i + 1];
                            break;
                        case "-op":
                            if (string.IsNullOrEmpty(args[i]))
                            {
                                Console.WriteLine("Must supply value for -op.");
                                return null;
                            }
                            argsObj.OutputPath = args[i + 1];
                            break;
                        case "-m":
                            if (string.IsNullOrEmpty(args[i]))
                            {
                                Console.WriteLine("Must supply value for -m.");
                                return null;
                            }
                            argsObj.Method = args[i].ToUpper();
                            break;
                        case "-ct":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ct.");
                                return null;
                            }
                            argsObj.ContentType = args[i];
                            break;
                        case "-t":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -t.");
                                return null;
                            }
                            argsObj.Timeout = int.Parse(args[i + 1]);
                            break;
                        case "-ua":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ua.");
                                return null;
                            }
                            argsObj.UserAgent = args[i + 1];
                            break;
                        case "-ka":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ka.");
                                return null;
                            }
                            argsObj.KeepAlive = bool.Parse(args[i + 1]);
                            break;
                        case "-re":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -re.");
                                return null;
                            }
                            argsObj.ResponseEncoding = EnumHelper.StringToEnum<Encoding>(args[i + 1]);
                            break;
                        case "-pde":
                            if (string.IsNullOrEmpty(args[i]))
                            {
                                Console.WriteLine("Must supply value for -pde.");
                                return null;
                            }
                            argsObj.PostDataEncoding = EnumHelper.StringToEnum<Encoding>(args[i + 1]);
                            break;
                        case "-pdp":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -pdp.");
                                return null;
                            }
                            argsObj.PostData = IOHelper.GetFileContent(args[i + 1]);
                            break;
                        case "-c:u":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -c:u.");
                                return null;
                            }
                            argsObj.CredentialUsername = args[i + 1];
                            break;
                        case "-c:p":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -c:p.");
                                return null;
                            }
                            argsObj.CredentialPassword = args[i + 1];
                            break;
                        case "-o:d":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -o:d.");
                                return null;
                            }
                            argsObj.CredentialDomain = args[i + 1];
                            break;
                        case "-ps:bl":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps:bl.");
                                return null;
                            }
                            argsObj.ProxyBypassLocally = bool.Parse(args[i + 1]);
                            break;
                        case "-ps:a":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps:a.");
                                return null;
                            }
                            argsObj.ProxyAddress = args[i + 1];
                            break;
                        case "-ps:c:u":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps:c:u.");
                                return null;
                            }
                            argsObj.ProxyCredentialUsername = args[i + 1];
                            break;
                        case "-ps:c:p":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps.c.p.");
                                return null;
                            }
                            argsObj.ProxyCredentialPassword = args[i + 1];
                            break;
                        case "-ps:c:d":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps:c:d.");
                                return null;
                            }
                            argsObj.ProxyCredentialDomain = args[i + 1];
                            break;
                        case "-ps:ab":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ps:ab.");
                                return null;
                            }
                            if (argsObj.ProxyAddBypassRule == null) argsObj.ProxyAddBypassRule = new ArrayList();
                            argsObj.ProxyAddBypassRule.Add(args[i + 1]);
                            break;
                        case "-hd":
                            if (string.IsNullOrEmpty(args[i + 1]))
                            {
                                Console.WriteLine("Must supply value for -ha.");
                                return null;
                            }
                            if (argsObj.Header == null) argsObj.Header = new WebHeaderCollection();
                            argsObj.Header.Add(args[i + 1]);
                            break;
                    }
                }
                return argsObj;
            }

            return null;

            //Console.WriteLine("Must call http command with valid arguments.");
            //HttpHelp();
        }
        private static bool ValidateArgs(HttpArgs args)
        {
            if (args == null)
            {
                Console.WriteLine("No values have been supplied");
                return false;
            }
            if (args.Help)
            {
                HttpHelp();
                return false;
            }
            if (string.IsNullOrEmpty(args.Url))
            {
                Console.WriteLine("Url must be supplied.");
                return false;
            }
            if (!string.IsNullOrEmpty(args.ProxyCredentialUsername) &&
                !string.IsNullOrEmpty(args.ProxyCredentialPassword))
            {
                if (!string.IsNullOrEmpty(args.ProxyCredentialDomain))
                {
                    args.Proxy.Credentials = new NetworkCredential(args.ProxyCredentialUsername,
                                                                   args.ProxyCredentialPassword,
                                                                   args.ProxyCredentialDomain);
                }
                else
                {
                    args.Proxy.Credentials = new NetworkCredential(args.ProxyCredentialUsername,
                                                                   args.ProxyCredentialPassword);
                }
            }
            if (args.ProxyAddBypassRule != null && args.ProxyAddBypassRule.Count > 0)
            {
                foreach (var bypass in args.ProxyAddBypassRule)
                    args.Proxy.BypassArrayList.Add(bypass);
            }

            return true;
        }
        private static void SendHttpRequest(HttpArgs args)
        {
            if (ValidateArgs(args))
            {
                var http = new HttpHelper();

                if (args.Header != null && args.Header.Count > 0)
                    http.WebHeaderCollection = args.Header;

                //Console.WriteLine(args.Url);
                var response = http.SendRequest(
                    args.Url,
                    args.PostData,
                    args.Method,
                    args.ContentType,
                    args.UserAgent,
                    args.KeepAlive,
                    args.Credential,
                    args.Proxy,
                    args.Timeout,
                    args.ResponseEncoding);

                if (!string.IsNullOrEmpty(args.OutputPath))
                {
                    using (var writer = new StreamWriter(args.OutputPath)) writer.WriteLine(response);
                }
                else
                {
                    Console.WriteLine(response);
                }

                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("");
                Console.WriteLine("Request was successfully made.");
            }
        }
        private class HttpArgs
        {
            public string Url { get; set; }
            public bool Help { get; set; }
            public string OutputPath { get; set; }
            private string _method;
            public string Method
            {
                get { return _method ?? "GET"; }
                set { _method = value; }
            }
            public string ContentType { get; set; }
            private int? _timeout = null;
            public int? Timeout
            {
                get
                {
                    return _timeout;
                }
                set
                {
                    _timeout = value;
                }
            }
            public string UserAgent { get; set; }
            private bool? _keepAlive = null;
            public bool? KeepAlive
            {
                get
                {
                    return _keepAlive;
                }
                set
                {
                    _keepAlive = value;
                }
            }
            public Encoding ResponseEncoding { get; set; }
            public Encoding PostDataEncoding { get; set; }
            public string PostData { get; set; }

            public NetworkCredential Credential { get; set; }
            private string _credentialUsername;
            public string CredentialUsername
            {
                get
                {
                    return _credentialUsername;
                }
                set
                {
                    if (Credential == null) Credential = new NetworkCredential();
                    Credential.UserName = value;
                    _credentialUsername = value;
                }
            }
            private string _credentialPassword;
            public string CredentialPassword
            {
                get
                {
                    return _credentialPassword;
                }
                set
                {
                    if (Credential == null) Credential = new NetworkCredential();
                    Credential.Password = value;
                    _credentialPassword = value;
                }
            }
            private string _credentialDomaon;
            public string CredentialDomain
            {
                get
                {
                    return _credentialDomaon;
                }
                set
                {
                    if (Credential == null) Credential = new NetworkCredential();
                    Credential.Domain = value;
                    _credentialDomaon = value;
                }
            }

            public WebProxy Proxy { get; set; }
            private bool _proxyBypassLocally;
            public bool ProxyBypassLocally
            {
                get
                {
                    return _proxyBypassLocally;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    Proxy.BypassProxyOnLocal = value;
                    _proxyBypassLocally = value;
                }
            }
            private string _proxyAddress;
            public string ProxyAddress
            {
                get
                {
                    return _proxyAddress;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    Proxy.Address = new Uri(value);
                    _proxyAddress = value;
                }
            }
            private string _proxyCredentialUsername;
            public string ProxyCredentialUsername
            {
                get
                {
                    return _proxyCredentialUsername;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    _proxyCredentialUsername = value;
                }
            }
            private string _proxyCredentialPassword;
            public string ProxyCredentialPassword
            {
                get
                {
                    return _proxyCredentialPassword;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    _proxyCredentialPassword = value;
                }
            }
            private string _proxyCredentialDomain;
            public string ProxyCredentialDomain
            {
                get
                {
                    return _proxyCredentialDomain;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    _proxyCredentialDomain = value;
                }
            }
            private ArrayList _proxyAddBypassRule;
            public ArrayList ProxyAddBypassRule
            {
                get
                {
                    return _proxyAddBypassRule;
                }
                set
                {
                    if (Proxy == null) Proxy = new WebProxy();
                    if (_proxyAddBypassRule == null) _proxyAddBypassRule = new ArrayList();
                    _proxyAddBypassRule.Add(value);
                }
            }

            public WebHeaderCollection Header { get; set; }
        }

        #region other stuff
        private static void SendFluentHttpRequest()
        {
            var response = new FluentHttp()
                .ContentType("text/xml")
                .Credentials("username", "password", "domain")
                .Encoding(Encoding.UTF8)
                .KeepAlive(true)
                .Method("POST")
                .PostData("put some xml or json or whatever you want :)")
                .PostDataEncoding(Encoding.ASCII)
                .Timeout(60000)
                .Url("www.google.com")
                .UserAgent("Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.55 Safari/533.4")
                .Proxy(p => p
                    .AddBypassRule("")
                    .AddBypassRule("")
                    .Address("")
                    .BypassLocally()
                    .Credentials("proxyUsername", "proxyPassword", "proxyDomain"))
                .Headers(h => h
                    .AddRequestHeader("Accept-Language:da")
                    .AddRequestHeader("Accept-Language", "en;q=0.8")
                    .AddRequestHeader(HttpRequestHeader.AcceptCharset, "ISO-8859-1,UTF-8;q=0.7,*;q=0.7")
                    .AddResponseHeader(HttpResponseHeader.CacheControl, "private"))
                .Send();
        }
        private static void BuildUrl()
        {
            var u = new UrlBuilder();
            var url = u.BaseUrl("http://www.google.pt/")
                .Parameters(p => p
                    .Add("parameter_a", "parameter_a_value")
                    .Add("parameter_b", "parameter_b_value")
                    .Add("name", "Andre Carrilho"))
                .Build();

            Console.WriteLine(url);
        }
        private static void SendMail()
        {
            var mailsWithDisplayNames = new Dictionary<string, string>
            {
                {"Another Person", "another.person@anothermail.com"},
                {"Yet Another Person","yet.another.person@anothermail.com"}
            };

            var justMails = new List<string>
    {
        "wow.another.person@anothermail.com",
        "ok.another.person@anothermail.com"
    };

            var mailHelper = new MailHelper("smtp.gmail.com", 587);
            mailHelper
                .From("Andre Carrilho", "me@mymail.com")
                .To(to => to.Add("Andre Carrilho", "anotherme@mymail.com"))
                .Bcc(bcc => bcc.Add(mailsWithDisplayNames))
                .Cc(cc => cc.Add(justMails))
                .Body("Trying out the MailHelper class with some Html: <p style='font-weight:bold;color:blue;font-size:32px;'>html</p>")
                .Subject("Testing Fluent MailHelper")
                .IsBodyHtml(true)
                .Credentials("someUser", "somePass")
                .Port(1234)
                .Ssl(true)
                .Send();

            Console.ReadLine();
        }
        private static void DataContractJsonSerialization()
        {
            var obj = new SampleObject
                            {
                                Id = Guid.NewGuid(),
                                Name = "André",
                                AnotherObject = new SampleObject.SubObject
                                                    {
                                                        Age = 24,
                                                        Birthdate = DateTime.Now
                                                    }
                            };

            var jsonSer = new DataContractSerializerHelper<SampleObject>();
            var stringObj = jsonSer.SerializeToJsonString(obj, Encoding.UTF8);

            Console.WriteLine(stringObj);
            Console.WriteLine("Done serializing to json");

            var deserializedObj = jsonSer.DeserializeFromJsonString(stringObj, Encoding.UTF8);

            jsonSer.SerializeToJsonFile(@"c:\temp\jsonObject.json", obj, Encoding.UTF8);

            var deserializedObj1 = jsonSer.DeserializeFromJsonFile(@"c:\temp\jsonObject.json", Encoding.UTF8);

            Console.WriteLine(deserializedObj.Id);
            Console.WriteLine(deserializedObj.Name);
            Console.WriteLine(deserializedObj.AnotherObject.Age);
            Console.WriteLine(deserializedObj.AnotherObject.Birthdate);
            Console.WriteLine("Done deserializing to json");

            var path = Console.ReadLine();
            jsonSer.SerializeToJsonFile(path, obj, Encoding.UTF8);

            var deserializeFiledObj = jsonSer.DeserializeFromJsonFile(path, Encoding.UTF8);

            Console.WriteLine(deserializeFiledObj.Id);
            Console.WriteLine(deserializeFiledObj.Name);
            Console.WriteLine(deserializeFiledObj.AnotherObject.Age);
            Console.WriteLine(deserializeFiledObj.AnotherObject.Birthdate);
            Console.WriteLine("Done deserializing from json file");
        }
        private static void SendHttpRequest()
        {
            string site;
            string logPath;
            string exit = String.Empty;

            while (!String.Equals(exit, "exit"))
            {
                try
                {
                    Console.Write("Type the url: ");
                    site = Console.ReadLine();
                    Console.Write("Type the output file path: ");
                    logPath = Console.ReadLine();

                    HttpHelper http = new HttpHelper();

                    Console.WriteLine();
                    Console.Write("Do you wish to add header values [true | false]: ");
                    bool addMore = bool.Parse(Console.ReadLine());
                    while (addMore)
                    {
                        Console.Write("Key name: ");
                        string key = Console.ReadLine();

                        Console.Write("Key value: ");
                        string value = Console.ReadLine();

                        if (http.WebHeaderCollection == null) http.WebHeaderCollection = new System.Net.WebHeaderCollection();
                        http.WebHeaderCollection.Add(key, value);

                        Console.WriteLine();
                        Console.Write("Do you wish to add more header values [true | false]: ");
                        addMore = bool.Parse(Console.ReadLine());
                    }

                    string content = http.SendRequest(site, null, "GET", null, null,
                        true, null, null, null, Encoding.UTF8);

                    using (TextWriter txt = new StreamWriter(logPath))
                        txt.WriteLine(content);

                    //http.DownloadFile(site, logPath);

                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine("Everything went well.");
                }
                catch (Exception ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Error: {0}", ex.Message);
                }

                Console.WriteLine();
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write("Type 'exit' to leave or press [Enter] to send another request: ");
                exit = Console.ReadLine();
            }
        }
        #endregion
    }
}
